package ml.practicum.table;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import ml.practicum.feature.FeatureFactory;
import ml.practicum.feature.LVFeature;
import ml.practicum.util.Percist;

public class HeaderFactory {
	
	public static List<LVFeature<String>> create(File propertiesFile, HeadedTable<String,String> data ){
		List<LVFeature<String>> result = new ArrayList<LVFeature<String>>();
		Properties properties = new Properties();
		try {
			properties.load(new FileInputStream(propertiesFile));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		                  
		int maxBins = new  Double((Math.pow(data.getRowCount(),1./data.getColumnCount())-1.)*data.getColumnCount()+1).intValue(); 
		for(int i = 0;  i< data.getColumnCount();i++ ){
			result.add(FeatureFactory.create(data.getHeader().get(i),(Set<String>)new HashSet<String>(data.getColumn(i)),maxBins,properties));
		}
		return result;
	}
	
	/**
	 * Gets header with feature setting, if it is not stored yet
	 * use the table and cli to set the settings;  
	 * @param data full data set;
	 * @param headerSettings file with header settings
	 * @return header with feature settings
	 */
	@SuppressWarnings("unchecked")
	public static LVFeature<String> [] create(HeadedTable<String,String> data, File headerSettings){
		List<String> input = data.getHeader();
		List<LVFeature<String>> result = null;
		//URL settingsResource  = HeaderTableFactory.class.getResource(String.format("/headerSettings/%s.serial",concat(header)));
		if (headerSettings.exists()){
			List<LVFeature<String>>  storedHeader = (List<LVFeature<String>>) Percist.load(headerSettings);
			if (sameHeader(input,storedHeader )){
				result = storedHeader;
			}else{
				//TODO: throw some error;
				System.err.println("header is not the same");
			}
		}else{
			result = create(data);
			Percist.store(headerSettings, result);
		}
		return (LVFeature<String>[]) result.toArray(new LVFeature[0]);
	}
	
	
	/**
	 * use the data table and cli to set the settings;  
	 * @param data full data set;
	 * @return header with feature settings
	 */	
	@SuppressWarnings("deprecation")
	public static List<LVFeature<String>> create(HeadedTable<String,String> data){
		List<String> input = data.getHeader();
		List<LVFeature<String>> result = new ArrayList<LVFeature<String>>();
		for (String label:input){
			result.add(FeatureFactory.create(label,System.in, System.out,data));
		}
		return result;
	}
	
	/**
	 * FIXME: this method maybe doesn't belong here
	 * Should return true as long as the stored header has the same features
	 * or more
	 * @param labels	header with String feature labels
	 * @param LVFeatures of Features with String labels.
	 * @return true if the Feature header could describe the String Labels   
	 */
	private static boolean sameHeader(List<String>labels, List<LVFeature<String>> LVFeatures){
		for (int i=0; i< labels.size(); i++){
			if(!labels.get(i).equals(LVFeatures.get(i).getLabel())){
				return false;
			}
		}
		return true;
	}
}
